/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.diagram.deployment;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.gef.palette.MarqueeToolEntry;
import org.eclipse.gef.palette.PaletteContainer;
import org.eclipse.gef.palette.PaletteDrawer;
import org.eclipse.gef.palette.PaletteEntry;
import org.eclipse.gef.palette.PaletteGroup;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.palette.PaletteSeparator;
import org.eclipse.gef.palette.PaletteStack;
import org.eclipse.gef.palette.PanningSelectionToolEntry;
import org.eclipse.gef.palette.ToolEntry;
import org.eclipse.gef.ui.palette.FlyoutPaletteComposite.FlyoutPreferences;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.uml2.uml.Abstraction;
import org.eclipse.uml2.uml.Artifact;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.CommunicationPath;
import org.eclipse.uml2.uml.Constraint;
import org.eclipse.uml2.uml.DataType;
import org.eclipse.uml2.uml.Dependency;
import org.eclipse.uml2.uml.Deployment;
import org.eclipse.uml2.uml.DeploymentSpecification;
import org.eclipse.uml2.uml.Device;
import org.eclipse.uml2.uml.Enumeration;
import org.eclipse.uml2.uml.ExecutionEnvironment;
import org.eclipse.uml2.uml.Generalization;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.Interface;
import org.eclipse.uml2.uml.Manifestation;
import org.eclipse.uml2.uml.Node;
import org.eclipse.uml2.uml.PackageImport;
import org.eclipse.uml2.uml.PrimitiveType;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Realization;
import org.eclipse.uml2.uml.Signal;
import org.eclipse.uml2.uml.Slot;
import org.eclipse.uml2.uml.Usage;

import com.cea.papyrus.core.IPapyrusUIConstants;
import com.cea.papyrus.core.PapyrusMessages;
import com.cea.papyrus.core.PapyrusPlugin;
import com.cea.papyrus.core.editor.CreationEntryFactory;
import com.cea.papyrus.core.editor.DiagramPalette;
import com.cea.papyrus.core.pseudoelement.GraphicalLink;
import com.cea.papyrus.core.pseudoelement.InstanceSpecificationLink;
import com.cea.papyrus.core.ui.dialogs.PapyrusMessageDialog;

/**
 * Manages creation of the palette in the deployment diagram editor.
 * 
 * @author Gilles Cannenterre
 * @since 15 janv. 07
 */
public final class DeploymentDiagramPaletteFactory extends CreationEntryFactory {

	/**
	 * The Constant PALETTE_DOCK_LOCATION.
	 */
	private static final String PALETTE_DOCK_LOCATION = "ShapesEditorPaletteFactory.Location";

	/**
	 * The Constant PALETTE_SIZE.
	 */
	private static final String PALETTE_SIZE = "ShapesEditorPaletteFactory.Size";

	/**
	 * The Constant PALETTE_STATE.
	 */
	private static final String PALETTE_STATE = "ShapesEditorPaletteFactory.State";

	/**
	 * Creates the shapes drawer.
	 * 
	 * @return the palette container
	 */
	private static PaletteContainer createShapesDrawer() {
		PaletteDrawer componentsDrawer = new PaletteDrawer("Uml Element");

		// Begin of entry stack for Package, model and profile creation
		List<PaletteEntry> entries = new ArrayList<PaletteEntry>();
		try {
			// Package creation
			entries.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddPackageCommand_Label,
							PapyrusMessages.AddPackageCommand_Description,
							org.eclipse.uml2.uml.Package.class, null));

			// Begin of entry stack for node, device, execution environment
			PaletteStack paletteStack = new PaletteStack("", "", null);
			// Node creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddNodeCommand_Label,
							PapyrusMessages.AddNodeCommand_Description,
							Node.class, null));
			// Device creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddDeviceCommand_Label,
							PapyrusMessages.AddDeviceCommand_Description,
							Device.class, null));
			// ExecutionEnvironment creation
			paletteStack
					.add(PapyrusPlugin.creationToolFactory
							.getCombinedTemplateCreationToolEntry(
									PapyrusMessages.AddExecutionEnvironmentCommand_Label,
									PapyrusMessages.AddExecutionEnvironmentCommand_Description,
									ExecutionEnvironment.class, null));
			entries.add(paletteStack);
			// End of palette stack for node, device, execution environment

			// Begin of entry stack for artifact and deployment specification
			paletteStack = new PaletteStack("", "", null);
			// Artifact creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddArtifactCommand_Label,
							PapyrusMessages.AddArtifactCommand_Description,
							Artifact.class, null));
			// DeploymentSpecification creation
			paletteStack
					.add(PapyrusPlugin.creationToolFactory
							.getCombinedTemplateCreationToolEntry(
									PapyrusMessages.AddDeploymentSpecificationCommand_Label,
									PapyrusMessages.AddDeploymentSpecificationCommand_Description,
									DeploymentSpecification.class, null));
			entries.add(paletteStack);
			// End of palette stack for artifact and deployment specification
			
			// InstanceSpecification creation
			entries.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddInstanceSpecificationCommand_Label,
							PapyrusMessages.AddInstanceSpecificationCommand_Description,
							InstanceSpecification.class, null));
			
			entries.add(PapyrusPlugin.creationToolFactory.getCombinedTemplateCreationToolEntry(
					PapyrusMessages.AddPropertyCommand_Label
					, PapyrusMessages.AddPropertyCommand_Description
					, Property.class
					, null));
			
			// Slot creation
			entries.add(PapyrusPlugin.creationToolFactory.getCombinedTemplateCreationToolEntry(
					PapyrusMessages.AddSlotCommand_Label
					, PapyrusMessages.AddSlotCommand_Description
					, Slot.class
					, null));
			
			// Begin of entry stack for Class, Interface,Signal and InstanceSpecificationcreation
			paletteStack = new PaletteStack("", "", null);
			// Class creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddClassCommand_Label,
							PapyrusMessages.AddClassCommand_Description,
							Class.class, null));
			// Interface creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddInterfaceCommand_Label,
							PapyrusMessages.AddInterfaceCommand_Description,
							Interface.class, null));
			// Signal creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddSignalCommand_Label,
							PapyrusMessages.AddSignalCommand_Description,
							Signal.class, null));
			entries.add(paletteStack);
			// End of palette stack for Class, Interface, Signal and InstanceSpecification creation

			// Begin of palette stack for DataType, Enummeration and
			// PrimitiveType
			paletteStack = new PaletteStack("", "", null);
			// Primitive type creation
			paletteStack
					.add(PapyrusPlugin.creationToolFactory
							.getCombinedTemplateCreationToolEntry(
									PapyrusMessages.AddPrimitiveTypeCommand_Label,
									PapyrusMessages.AddPrimitiveTypeCommand_Description,
									PrimitiveType.class, null));
			// Datatype creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddDataTypeCommand_Label,
							PapyrusMessages.AddDataTypeCommand_Description,
							DataType.class, null));
			// Enumeration creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddEnumerationCommand_Label,
							PapyrusMessages.AddEnumerationCommand_Description,
							Enumeration.class, null));
			entries.add(paletteStack);
			// End of palette stack for DataType, Enummeration and PrimitiveType

			// Comment creation
			entries.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddCommentCommand_Label,
							PapyrusMessages.AddCommentCommand_Description,
							Comment.class, null));
			// Constraint creation
			entries.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddConstraintCommand_Label,
							PapyrusMessages.AddConstraintCommand_Description,
							Constraint.class, null));			
		} catch (Exception e) {
			PapyrusMessageDialog.display(e.getMessage(), e);
		}

		componentsDrawer.addAll(entries);

		return componentsDrawer;
	}

	/**
	 * Creates the PaletteRoot and adds all palette elements. Use this factory
	 * method to create a new palette for your graphical editor.
	 * 
	 * @return a new PaletteRoot
	 */
	public static DiagramPalette createPalette() {
		DiagramPalette palette = new DiagramPalette(IPapyrusUIConstants.DEPLOYMENT_DIAGRAM);
		palette.add(createToolsGroup(palette));
		palette.add(createShapesDrawer());

		// Create additionnal menu defined in extensions
		palette.createMenuExtensions();

		return palette;
	}

	/**
	 * Return a FlyoutPreferences instance used to save/load the preferences of
	 * a flyout palette.
	 * 
	 * @return the flyout preferences
	 */
	static FlyoutPreferences createPalettePreferences() {
		return new FlyoutPreferences() {
			private IPreferenceStore getPreferenceStore() {
				return Activator.getDefault().getPreferenceStore();
			}

			public int getDockLocation() {
				return getPreferenceStore().getInt(PALETTE_DOCK_LOCATION);
			}

			public int getPaletteState() {
				return getPreferenceStore().getInt(PALETTE_STATE);
			}

			public int getPaletteWidth() {
				return getPreferenceStore().getInt(PALETTE_SIZE);
			}

			public void setDockLocation(int location) {
				getPreferenceStore().setValue(PALETTE_DOCK_LOCATION, location);
			}

			public void setPaletteState(int state) {
				getPreferenceStore().setValue(PALETTE_STATE, state);
			}

			public void setPaletteWidth(int width) {
				getPreferenceStore().setValue(PALETTE_SIZE, width);
			}
		};
	}

	/**
	 * Creates the tools group.
	 * 
	 * @param palette the palette
	 * 
	 * @return the palette container
	 */
	private static PaletteContainer createToolsGroup(PaletteRoot palette) {
		// PaletteDrawer componentsDrawer = new PaletteDrawer("RelationShips");
		PaletteGroup toolGroup = new PaletteGroup("RelationShips");

		// Add a selection tool to the group
		ToolEntry tool = new PanningSelectionToolEntry();
		toolGroup.add(tool);
		palette.setDefaultEntry(tool);

		// Add a marquee tool to the group
		toolGroup.add(new MarqueeToolEntry());

		// Add a (unnamed) separator to the group
		toolGroup.add(new PaletteSeparator());		
		List entries = new ArrayList();
		try {
			///////////////////////////////////////////////////////////////////
			// Begin of entry stack for Dependencies
			///////////////////////////////////////////////////////////////////
			PaletteStack paletteStack = new PaletteStack("", "", null);
			
			// Add Dependency connection tool
			paletteStack.add(PapyrusPlugin.creationToolFactory.getConnectionCreationToolEntry(
					PapyrusMessages.AddDependencyCommand_Label,
					PapyrusMessages.AddDependencyCommand_Description,
					Dependency.class,
					null));

			// Add Abstraction connection tool
			paletteStack.add(PapyrusPlugin.creationToolFactory.getConnectionCreationToolEntry(
					PapyrusMessages.AddAbstractionCommand_Label,
					PapyrusMessages.AddAbstractionCommand_Description,
					Abstraction.class,
					null));
			

			// Add Realization connection tool
			paletteStack.add(PapyrusPlugin.creationToolFactory.getConnectionCreationToolEntry(
					PapyrusMessages.AddRealizationCommand_Label,
					PapyrusMessages.AddRealizationCommand_Description,
					Realization.class,
					null));
			
			
			// Add Usage connection tool
			paletteStack.add(PapyrusPlugin.creationToolFactory.getConnectionCreationToolEntry(
					PapyrusMessages.AddUsageCommand_Label,
					PapyrusMessages.AddUsageCommand_Description,
					Usage.class,
					null));	
			
			// Add PackageImport
			paletteStack
					.add(PapyrusPlugin.creationToolFactory
							.getConnectionCreationToolEntry(
									PapyrusMessages.AddPackageImportCommand_Label,
									PapyrusMessages.AddPackageImportCommand_Description,
									PackageImport.class, null));
			// Add Deployment
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getConnectionCreationToolEntry(
							PapyrusMessages.AddDeploymentCommand_Label,
							PapyrusMessages.AddDeploymentCommand_Description,
							Deployment.class, null));
			// Add Manifestation
			paletteStack
					.add(PapyrusPlugin.creationToolFactory
							.getConnectionCreationToolEntry(
									PapyrusMessages.AddManifestationCommand_Label,
									PapyrusMessages.AddManifestationCommand_Description,
									Manifestation.class, null));
			entries.add(paletteStack);

			///////////////////////////////////////////////////////////////////
			// End of entry stack for Dependencies
			///////////////////////////////////////////////////////////////////

			// Add Generalization
			entries.add(PapyrusPlugin.creationToolFactory
							.getConnectionCreationToolEntry(
									PapyrusMessages.AddGeneralizationCommand_Label,
									PapyrusMessages.AddGeneralizationCommand_Description,
									Generalization.class, null));
			
			// Association palette stack
			paletteStack = new PaletteStack("", "", null);			
			// Add Association
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getConnectionCreationToolEntry(
							PapyrusMessages.AddAssociationCommand_Label,
							PapyrusMessages.AddAssociationCommand_Description,
							Association.class, null));			
			// Add CommunicationPath
			paletteStack.add(PapyrusPlugin.creationToolFactory
							.getConnectionCreationToolEntry(
									PapyrusMessages.AddCommunicationPathCommand_Label,
									PapyrusMessages.AddCommunicationPathCommand_Description,
									CommunicationPath.class, null));			
			// Add link
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getConnectionCreationToolEntry(
							PapyrusMessages.AddLinkCommand_Label,
							PapyrusMessages.AddLinkCommand_Description,
							InstanceSpecificationLink.class, null));		
			entries.add(paletteStack);
			// Association palette stack - end

			///////////////////////////////////////////////////////////////////
			// Begin of tool for Comment and constraint links
			///////////////////////////////////////////////////////////////////
			
			// Add GraphicalLink
			entries.add(PapyrusPlugin.creationToolFactory.getConnectionCreationToolEntry(
					PapyrusMessages.AddGraphicalLinkCommand_Label,
					PapyrusMessages.AddGraphicalLinkCommand_Description,
					GraphicalLink.class,
					null));	

		} catch (Exception e) {
			PapyrusMessageDialog.display(e.getMessage(), e);
		}

		toolGroup.addAll(entries);
		return toolGroup;
	}
}